package com.atguigu.myssm.basedao;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public abstract class BaseDAO<T> {
    public final String DRIVER = "com.mysql.jdbc.Driver" ;
    public final String URL = "jdbc:mysql://localhost:3306/fruitdb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
    public final String USER = "root";
    public final String PWD = "12345" ;

    protected Connection conn ;
    protected PreparedStatement psmt ;
    protected ResultSet rs ;

    //泛型的类类型，T的类型
    protected Class entityClass;


    public BaseDAO(){

        /**
         * getClass()是FruitDAOImpl的方法
         * 因为我们执行时候是创建FruitDAOImpl的实例，那么子类构造方法内部首先会先调用父类的无参构造
         * 因此此时getClass()会被执行，但是是获取的是FruitDAOImpl的Class
         */
        //获取父类的类型即获取FruitDAOImpl的父类BaseDAO
        Type genericType = getClass().getGenericSuperclass();
        Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
        Type actualType = actualTypeArguments[0];
        String typeName = actualType.getTypeName();
        try {
            entityClass = Class.forName(typeName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }




    /**
     * 获取JDBC连接对象
     * @return
     */
    protected Connection getConn(){
        try {
            //1.加载驱动
            Class.forName(DRIVER);
            //2.通过驱动管理器获取连接对象
            return DriverManager.getConnection(URL, USER, PWD);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return null ;
    }





    /**
     *  增删改的通用方法，执行更新，返回影响行数
     *  如果是插入操作，返回插入数据的主键值
     * @param sql
     * @param params
     * @return
     */
    protected int executeUpdate(String sql , Object... params){
        boolean insertFlag = false;
        insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
        try {
            conn = getConn();
            if (insertFlag){
                psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
            }else {
                psmt = conn.prepareStatement(sql);
            }
            setParams(psmt,params);
            int count = psmt.executeUpdate();
            if (insertFlag){
                rs = psmt.getGeneratedKeys();
                if (rs.next()){
                    //返回主键值，有些许bug，我们项目主键都是数字无所谓
                    return ((Long)(rs.getLong(1))).intValue();
                }
            }
            return count;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(rs,psmt,conn);
        }
        return 0;
    }

    /**
     * 为预编译对象注入查询条件
     * @param psmt
     * @param params
     * @throws SQLException
     */
    private void setParams(PreparedStatement psmt,Object... params) throws SQLException {
        if (psmt != null && params.length > 0){
            for (int i = 0; i < params.length; i++) {
                psmt.setObject(i+1,params[i]);
            }
        }
    }

    /**
     * 利用反射为对象的属性赋值
     * @param entity
     * @param property
     * @param propertyValue
     */
    private void setValue2Field(T entity,String property,Object propertyValue){
        Class clazz = entity.getClass();
        Field field = null;
        try {
            field = clazz.getDeclaredField(property);
            if (field!=null){
                field.setAccessible(true);
                field.set(entity,propertyValue);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    //执行复杂查询，返回例如统计结果
    protected Object[] executeComplexQuery(String sql , Object... params){
        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            rs = psmt.executeQuery();

            //通过rs可以获取结果集的元数据
            //元数据：描述结果集数据的数据 , 简单讲，就是这个结果集有哪些列，什么类型等等

            ResultSetMetaData rsmd = rs.getMetaData();
            //获取结果集的列数
            int columnCount = rsmd.getColumnCount();
            Object[] columnValueArr = new Object[columnCount];
            //6.解析rs
            if(rs.next()){
                for(int i = 0 ; i<columnCount;i++){
                    Object columnValue = rs.getObject(i+1);     //33    苹果      5
                    columnValueArr[i]=columnValue;
                }
                return columnValueArr ;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return null ;
    }



    /**
     * 查询单个数据
     * @param sql
     * @param params
     * @return
     */
    protected T queryEntity(String sql,Object... params){
        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            //执行查询
            rs = psmt.executeQuery();
            ResultSetMetaData metaData = psmt.getMetaData();
            //获取结果集列数
            int columnCount = metaData.getColumnCount();
            T entity = (T) entityClass.newInstance();
            //解析rs
            if(rs.next()){
                for (int i = 0; i < columnCount; i++) {
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    Object value = rs.getObject(i + 1);
                    setValue2Field(entity,columnLabel,value);
                }
                return entity;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return null;
    }


    /**
     * 查询多条数据
     * @param sql
     * @param params
     * @return
     */
    protected List<T> executeQuery(String sql,Object... params){
        List<T> entityList = new ArrayList<>();

        try {
            conn = getConn() ;
            psmt = conn.prepareStatement(sql);
            setParams(psmt,params);
            //执行查询
            rs = psmt.executeQuery();
            ResultSetMetaData metaData = psmt.getMetaData();
            //获取结果集列数
            int columnCount = metaData.getColumnCount();
            //解析rs
            while(rs.next()){
                T entity = (T) entityClass.newInstance();
                for (int i = 0; i < columnCount; i++) {
                    String columnLabel = metaData.getColumnLabel(i + 1);
                    Object value = rs.getObject(i + 1);
                    setValue2Field(entity,columnLabel,value);
                }
                entityList.add(entity);
            }
            return entityList;
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } finally {
            close(rs,psmt,conn);
        }
        return null;
    }



    /**
     * 关闭资源
     * @param rs
     * @param psmt
     * @param conn
     */
    protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
        try {
            if (rs != null) {
                rs.close();
            }
            if(psmt!=null){
                psmt.close();
            }
            if(conn!=null && !conn.isClosed()){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}





















